﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LoungeRepo.Contracts.Core;
using LoungeRepo.Normalizer;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;

namespace Test.LoungeRepo.Normalizer
{
    [TestFixture]
    public class testEntityRecognizer
    {
        [Test]
        public void Recognizes_ILoungeRepoEntities()
        {
            var e = new InterfaceBasedEntity();

            ILoungeRepoEntityIdentity ei;
            Assert.IsTrue(EntityRecognizer.TryExtractEntityIdentity(e, out ei));
            Assert.That(ei.Id, Is.EqualTo("42"));
            Assert.That(ei.Partition, Is.EqualTo("Arthur Dent"));
            Assert.AreSame(e, ei);
        }


        [Test]
        public void Recognizes_by_convention_Id_and_Partition_properties()
        {
            var e = new ConventionBasedEntity {Id = "42", Partition = "Arthur Dent"};

            ILoungeRepoEntityIdentity ei;
            Assert.IsTrue(EntityRecognizer.TryExtractEntityIdentity(e, out ei));
            Assert.That(ei.Id, Is.EqualTo("42"));
            Assert.That(ei.Partition, Is.EqualTo("Arthur Dent"));
            Assert.AreNotSame(e, ei);
        }


        [Test]
        public void Recognizes_by_convention_Id_property()
        {
            var e = new ConventionBasedEntityWithoutPartition { Id = "42" };

            ILoungeRepoEntityIdentity ei;
            Assert.IsTrue(EntityRecognizer.TryExtractEntityIdentity(e, out ei));
            Assert.That(ei.Id, Is.EqualTo("42"));
            Assert.AreEqual(ei.Partition, "");
            Assert.AreNotSame(e, ei);
        }


        [Test]
        public void Is_not_fooled_by_Partition_property()
        {
            var e = new NonEntityWithPartition();

            ILoungeRepoEntityIdentity ei;
            Assert.IsFalse(EntityRecognizer.TryExtractEntityIdentity(e, out ei));
        }

        [Test]
        public void Recognizes_by_convention_nonpublic_Id_property()
        {
            var e = new ConventionBasedEntityWithNonPublicId();

            ILoungeRepoEntityIdentity ei;
            Assert.IsTrue(EntityRecognizer.TryExtractEntityIdentity(e, out ei));
            Assert.That(ei.Id, Is.EqualTo("42"));
        }

        [Test]
        public void Recognizes_convention_based_entity_even_if_derived()
        {
            var e = new DerivedConventionBasedEntity();

            ILoungeRepoEntityIdentity ei;
            Assert.IsTrue(EntityRecognizer.TryExtractEntityIdentity(e, out ei));
            Assert.That(ei.Id, Is.EqualTo("42"));
        }

        [Test]
        public void Is_not_fooled_by_Id_of_wrong_type()
        {
            var e = new NonEntityWithIdOfWrongType();

            ILoungeRepoEntityIdentity ei;
            Assert.IsFalse(EntityRecognizer.TryExtractEntityIdentity(e, out ei));
        }


        [Test]
        public void Recognizes_entity_without_properties()
        {
            var e = new EntityWithoutIdProperty();

            ILoungeRepoEntityIdentity ei;
            Assert.IsTrue(EntityRecognizer.TryExtractEntityIdentity(e, out ei));
            Assert.That(ei.Id, Is.EqualTo("42"));
            Assert.That(ei.Partition, Is.EqualTo("Arthur Dent"));
        }
    }

    class InterfaceBasedEntity : ILoungeRepoEntityIdentity
    {
        #region Implementation of ILoungeRepoEntityIdentity

        public string Id
        {
            get { return "42"; }
        }

        public string Partition
        {
            get { return "Arthur Dent"; }
        }

        #endregion
    }


    class ConventionBasedEntity
    {
        public string Id { get; set; }
        public string Partition { get; set; }
    }

    class ConventionBasedEntityWithoutPartition
    {
        public string Id { get; set; }        
    }

    class NonEntityWithPartition
    {
        public string Partition { get; set; }
    }

    class ConventionBasedEntityWithNonPublicId
    {
        public ConventionBasedEntityWithNonPublicId()
        {
            this.Id = "42";
        }

        protected string Id { get; set; }
    }

    class DerivedConventionBasedEntity : ConventionBasedEntityWithNonPublicId
    {}

    class NonEntityWithIdOfWrongType
    {
        public int Id { get; set; }
    }


    class EntityWithoutIdProperty : ILoungeRepoEntity
    {
        #region Implementation of ILoungeRepoEntity

        public ILoungeRepoEntityIdentity GetPersistentId()
        {
            return new LoungeRepoEntityIdentity("42", "Arthur Dent");
        }

        #endregion
    }
}
